package com.rlz.base.base

import android.text.TextUtils
import androidx.lifecycle.MutableLiveData
import com.trello.rxlifecycle2.LifecycleTransformer
import com.rlz.base.base.Resource.Companion.error
import com.rlz.base.base.Resource.Companion.loading
import com.rlz.base.base.Resource.Companion.response
import com.rlz.base.util.DeviceUtils
import com.rlz.net.Interceptor.NetCacheInterceptor
import com.rlz.net.Interceptor.NetOfflineInterceptor
import com.rlz.net.NetManager
import com.rlz.net.NetParams
import com.rlz.net.NetParams.Companion.build
import io.reactivex.Observable
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
import java.net.ConnectException
import java.util.concurrent.TimeUnit

/**
 * Created by RLZ
 * on 2021/4/8
 * 数据请求的基类 为了解决减少大量的重复性的代码
 * 通过 setObjectLifecycleTransformer 绑定界面的生命周期
 * 通过LiveData分发数据
 * 通过setNetTags保证同意网络的请求只执行一次
 */
abstract class BaseModel {
    var mLifecycleTransformer: LifecycleTransformer<Any>? = null

    var mNetTags: MutableList<String?>? = null

    open fun <T> createService(service: Class<T>?): T {
        return NetManager.instance.getService(service)
    }

    open fun setObjectLifecycleTransformer(lifecycleTransformer: LifecycleTransformer<Any>?) {
        mLifecycleTransformer = lifecycleTransformer
    }


    open fun setNetTags(netTags: MutableList<String?>?) {
        mNetTags = netTags
    }

    open fun <T> observe(
        observable: Observable<*>,
        liveData: MutableLiveData<T>
    ): MutableLiveData<T>? {
        return observe(observable, liveData, null)
    }


    /**
     * 带参数的配置方式
     */
    open fun <T> observe(
        observable: Observable<*>,
        liveData: MutableLiveData<T>,
        p: NetParams?
    ): MutableLiveData<T>? {
        var netParams = p
        if (!DeviceUtils.isNetworkConnected()) {
            liveData.postValue(error<Any>(ConnectException()) as T)
            return liveData
        }
        if (netParams == null) {
            netParams = build()
        }
        val loadingMessage = netParams.getLoadingMessage()
        val isShowLoading = netParams.dialog()
        val offlineCacheTime = netParams.getOfflineCacheTime()
        if (offlineCacheTime > 0) setOfflineCacheTime(offlineCacheTime)
        val onlineCacheTime = netParams.getOnlineCacheTime()
        if (onlineCacheTime > 0) setOnlineCacheTime(onlineCacheTime)
        val oneTag = netParams.getOneTag()
        if (!TextUtils.isEmpty(oneTag)) {
            if (mNetTags!!.contains(oneTag)) {
                return liveData
            }
        }
        val maxCount = netParams.getRetryCount()
        val currentCount = intArrayOf(0)
        observable.subscribeOn(Schedulers.io())
            .retryWhen {
                if (currentCount[0] <= maxCount) {
                    currentCount[0]++
                    //延迟5秒后重连
                    return@retryWhen Observable.just(1)
                        .delay(5000, TimeUnit.MILLISECONDS)
                } else {
                    //如果已经到了重连次数就走异常
                    return@retryWhen Observable.error<Any>(Throwable("重连次数已最大,请求超时"))
                }
            }
            .observeOn(AndroidSchedulers.mainThread())
            .compose(mLifecycleTransformer)
            .doOnSubscribe {
                if (!TextUtils.isEmpty(oneTag)) mNetTags!!.add(oneTag)
                if (isShowLoading) liveData.postValue(
                    loading<Any>(
                        loadingMessage
                    ) as T
                )
            }
            .doFinally {
                if (!TextUtils.isEmpty(oneTag)) {
                    mNetTags!!.remove(oneTag)
                }
            }
            .subscribe(object : BaseObserver<Any?>() {
                override fun onSuccess(t: Any?) {
                    liveData.postValue(response(t as BaseResponse<T>) as T)
                }
            })
        return liveData
    }

    open fun setOnlineCacheTime(onlineCacheTime: Int) {
        NetCacheInterceptor.instance.setOnlineTime(onlineCacheTime)
    }


    open fun setOfflineCacheTime(cacheTime: Int) {
        NetOfflineInterceptor.instance.setOfflineCacheTime(cacheTime)
    }
}